sc: replace ScCaptionPtr with std::shared_ptr, tdf#117997, tdf#117228

Change-Id: I9b6a2c2504c9ce060906ac3bf156721709fef2f3
Reviewed-on: https://gerrit.libreoffice.org/55490
Tested-by: Jenkins
Reviewed-by: Eike Rathke <erack@redhat.com>
diff --git a/sc/inc/postit.hxx b/sc/inc/postit.hxx
index bf29a96..de77e20 100644
--- a/sc/inc/postit.hxx
+++ b/sc/inc/postit.hxx
@@ -36,110 +36,6 @@ class ScDocument;
namespace tools { class Rectangle; }
struct ScCaptionInitData;

/** Some desperate attempt to fight against the caption object ownership mess,
    to which none of shared/weak/plain pointer is a cure.
 */
class ScCaptionPtr
{
public:
    ScCaptionPtr();
    explicit ScCaptionPtr( SdrCaptionObj* p );
    ScCaptionPtr( const ScCaptionPtr& r );
    ScCaptionPtr( ScCaptionPtr&& r );
    ~ScCaptionPtr();

    ScCaptionPtr& operator=( const ScCaptionPtr& r );
    ScCaptionPtr& operator=( ScCaptionPtr&& r );
    explicit operator bool() const    { return mpCaption != nullptr; }
    const SdrCaptionObj* get() const        { return mpCaption; }
    SdrCaptionObj* get()        { return mpCaption; }
    const SdrCaptionObj* operator->() const { return mpCaption; }
    SdrCaptionObj* operator->() { return mpCaption; }
    const SdrCaptionObj& operator*() const  { return *mpCaption; }
    SdrCaptionObj& operator*()  { return *mpCaption; }

    // Does not default to nullptr to make it visually obvious where such is used.
    void reset( SdrCaptionObj* p );

    /** Insert to draw page. The caption object is owned by the draw page then.
     */
    void insertToDrawPage( SdrPage& rDrawPage );

    /** Remove from draw page. The caption object is not owned anymore by the
        draw page then.
     */
    void removeFromDrawPage( SdrPage& rDrawPage );

    /** Remove from draw page and free caption object if no Undo recording.
     */
    void removeFromDrawPageAndFree( bool bIgnoreUndo = false );

    /** Release all management of the SdrCaptionObj* in all instances of this
        list and dissolve. The SdrCaptionObj pointer returned is ready to be
        managed elsewhere.
     */
    SdrCaptionObj* release();

    /** Forget the SdrCaptionObj pointer in this one instance.
        Decrements a use count but does not destroy the object, it's up to the
        caller to manage this mess..
     */
    void forget();

    /** Flag that this instance is in Undo, so drawing layer owns it. */
    void setNotOwner();

    oslInterlockedCount getRefs() const;

private:

    struct Head
    {
        ScCaptionPtr*       mpFirst;        ///< first in list
        oslInterlockedCount mnRefs;         ///< use count

        Head() = delete;
        explicit Head( ScCaptionPtr* );
    };

    Head*                 mpHead;       ///< points to the "master" entry
    mutable ScCaptionPtr* mpNext;       ///< next in list
    SdrCaptionObj*        mpCaption;    ///< the caption object, managed by head master
    bool                  mbNotOwner;   ///< whether this caption object is owned by something else, e.g. held in Undo
                                            /* TODO: can that be moved to Head?
                                             * It's unclear when to reset, so
                                             * each instance has its own flag.
                                             * The last reference count
                                             * decrement automatically has the
                                             * then current state available.
                                             * */

    void newHead();             //< Allocate a new Head and init.
    void incRef() const;
    bool decRef() const;        //< @returns <TRUE/> if the last reference was decremented.
    void decRefAndDestroy();    //< Destroys caption object if the last reference was decremented.

    /** Remove from current list and close gap.

        Usually there are only very few instances, so maintaining a doubly
        linked list isn't worth memory/performance wise and a simple walk does
        it.
     */
    void removeFromList();

    /** Replace this instance with pNew in a list, if any.

        Used by move-ctor and move assignment operator.
     */
    void replaceInList( ScCaptionPtr* pNew );

    /** Dissolve list when the caption object is released or gone. */
    void dissolve();

    /** Just clear everything, while dissolving the list. */
    void clear();
};

/** Internal data for a cell annotation. */
struct SC_DLLPUBLIC ScNoteData
{
@@ -148,7 +44,7 @@ struct SC_DLLPUBLIC ScNoteData
    OUString     maDate;             /// Creation date of the note.
    OUString     maAuthor;           /// Author of the note.
    ScCaptionInitDataRef mxInitData;        /// Initial data for invisible notes without SdrObject.
    ScCaptionPtr        mxCaption;          /// Drawing object representing the cell note.
    std::shared_ptr< SdrCaptionObj >    m_pCaption;          /// Drawing object representing the cell note.
    bool                mbShown;            /// True = note is visible.

    explicit            ScNoteData( bool bShown = false );
@@ -235,12 +131,12 @@ public:
        contains initial caption data needed to construct a caption object.
        The SdrCaptionObj* returned is still managed by the underlying
        ScNoteData::ScCaptionPtr and must not be stored elsewhere. */
    SdrCaptionObj*      GetCaption() const { return maNoteData.mxCaption.get();}
    const std::shared_ptr< SdrCaptionObj>& GetCaption() const { return maNoteData.m_pCaption; }
    /** Returns the caption object of this note. Creates the caption object, if
        the note contains initial caption data instead of the caption.
        The SdrCaptionObj* returned is still managed by the underlying
        ScNoteData::ScCaptionPtr and must not be stored elsewhere. */
    SdrCaptionObj*      GetOrCreateCaption( const ScAddress& rPos ) const;
    const std::shared_ptr< SdrCaptionObj>& GetOrCreateCaption( const ScAddress& rPos ) const;

    /** Forgets the pointer to the note caption object.

@@ -268,7 +164,7 @@ private:
    /** Creates the caption object from initial caption data if existing. */
    void                CreateCaptionFromInitData( const ScAddress& rPos ) const;
    /** Creates a new caption object at the passed cell position, clones passed existing caption. */
    void                CreateCaption( const ScAddress& rPos, const SdrCaptionObj* pCaption = nullptr );
    void                CreateCaption( const ScAddress& rPos, const std::shared_ptr< SdrCaptionObj >& pCaption );
    /** Removes the caption object from the drawing layer, if this note is its owner. */
    void                RemoveCaption();

@@ -283,7 +179,7 @@ class SC_DLLPUBLIC ScNoteUtil
public:

    /** Creates and returns a caption object for a temporary caption. */
    static ScCaptionPtr CreateTempCaption( ScDocument& rDoc, const ScAddress& rPos,
    static std::shared_ptr< SdrCaptionObj > CreateTempCaption( ScDocument& rDoc, const ScAddress& rPos,
                            SdrPage& rDrawPage, const OUString& rUserText,
                            const tools::Rectangle& rVisRect, bool bTailFront );

diff --git a/sc/inc/scmod.hxx b/sc/inc/scmod.hxx
index 6d75e15..8349274 100644
--- a/sc/inc/scmod.hxx
+++ b/sc/inc/scmod.hxx
@@ -147,8 +147,6 @@ public:
    void                SetDragJump(
        ScDocument* pLocalDoc, const OUString& rTarget, const OUString& rText );

    static ScDocument*  GetClipDoc();       // called from document - should be removed later

    //  X selection:
    ScSelectionTransferObj* GetSelectionTransfer() const    { return m_pSelTransfer; }
    void                SetSelectionTransfer( ScSelectionTransferObj* pNew );
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index b836076..6fb5210 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -5339,7 +5339,7 @@ void Test::testNoteLifeCycle()

    // Re-insert the note back to the same place.
    m_pDoc->SetNote(aPos, pNote);
    SdrCaptionObj* pCaption = pNote->GetOrCreateCaption(aPos);
    SdrCaptionObj* pCaption = pNote->GetOrCreateCaption(aPos).get();
    CPPUNIT_ASSERT_MESSAGE("Failed to create a caption object.", pCaption);
    CPPUNIT_ASSERT_EQUAL_MESSAGE("This caption should belong to the drawing layer of the document.",
                           m_pDoc->GetDrawLayer(), static_cast<ScDrawLayer*>(&pCaption->getSdrModelFromSdrObject()));
@@ -5355,7 +5355,7 @@ void Test::testNoteLifeCycle()
    ScPostIt* pClipNote = aClipDoc.GetNote(aPos);
    CPPUNIT_ASSERT_MESSAGE("Failed to copy note to the clipboard.", pClipNote);
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Note on the clipboard should share the same caption object from the original.",
                           pCaption, pClipNote->GetCaption());
                           pCaption, pClipNote->GetCaption().get());


    // Move B2 to B3 with note, which creates an ScUndoDragDrop, and Undo.
@@ -5363,7 +5363,7 @@ void Test::testNoteLifeCycle()
    ScAddress aOrigPos(aPos);
    ScAddress aMovePos(1,2,0);
    ScPostIt* pOrigNote = m_pDoc->GetNote(aOrigPos);
    const SdrCaptionObj* pOrigCaption = pOrigNote->GetOrCreateCaption(aOrigPos);
    const SdrCaptionObj* pOrigCaption = pOrigNote->GetOrCreateCaption(aOrigPos).get();
    bool const bCut = true;       // like Drag&Drop
    bool bRecord = true;    // record Undo
    bool const bPaint = false;    // don't care about
@@ -5381,7 +5381,7 @@ void Test::testNoteLifeCycle()
    // The caption object should not be identical, it was newly created upon
    // Drop from clipboard.
    // pOrigCaption is a dangling pointer.
    const SdrCaptionObj* pMoveCaption = pMoveNote->GetOrCreateCaption(aMovePos);
    const SdrCaptionObj* pMoveCaption = pMoveNote->GetOrCreateCaption(aMovePos).get();
    CPPUNIT_ASSERT_MESSAGE("Captions identical after move.", pOrigCaption != pMoveCaption);

    SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
@@ -5396,7 +5396,7 @@ void Test::testNoteLifeCycle()

    // The caption object still should not be identical.
    // pMoveCaption is a dangling pointer.
    pOrigCaption = pOrigNote->GetOrCreateCaption(aOrigPos);
    pOrigCaption = pOrigNote->GetOrCreateCaption(aOrigPos).get();
    CPPUNIT_ASSERT_MESSAGE("Captions identical after move undo.", pOrigCaption != pMoveCaption);


@@ -5405,7 +5405,7 @@ void Test::testNoteLifeCycle()
    ScAddress aPosB4(1,3,0);
    ScPostIt* pNoteB4 = m_pDoc->GetOrCreateNote(aPosB4);
    CPPUNIT_ASSERT_MESSAGE("Failed to insert cell comment at B4.", pNoteB4);
    const SdrCaptionObj* pCaptionB4 = pNoteB4->GetOrCreateCaption(aPosB4);
    const SdrCaptionObj* pCaptionB4 = pNoteB4->GetOrCreateCaption(aPosB4).get();
    ScCellMergeOption aCellMergeOption(1,3,2,3);
    rDocFunc.MergeCells( aCellMergeOption, true /*bContents*/, bRecord, bApi, false /*bEmptyMergedCells*/ );

@@ -5417,7 +5417,7 @@ void Test::testNoteLifeCycle()
    // at B4 after the merge and not cloned nor recreated during Undo.
    ScPostIt* pUndoNoteB4 = m_pDoc->GetNote(aPosB4);
    CPPUNIT_ASSERT_MESSAGE("No cell comment at B4 after Undo.", pUndoNoteB4);
    const SdrCaptionObj* pUndoCaptionB4 = pUndoNoteB4->GetCaption();
    const SdrCaptionObj* pUndoCaptionB4 = pUndoNoteB4->GetCaption().get();
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Captions not identical after Merge Undo.", pCaptionB4, pUndoCaptionB4);


@@ -5433,7 +5433,7 @@ void Test::testNoteLifeCycle()
        ScAddress aPosB5(1,4,0);
        ScPostIt* pOtherNoteB5 = pDoc2->GetOrCreateNote(aPosB5);
        CPPUNIT_ASSERT_MESSAGE("Failed to insert cell comment at B5.", pOtherNoteB5);
        const SdrCaptionObj* pOtherCaptionB5 = pOtherNoteB5->GetOrCreateCaption(aPosB5);
        const SdrCaptionObj* pOtherCaptionB5 = pOtherNoteB5->GetOrCreateCaption(aPosB5).get();
        CPPUNIT_ASSERT_MESSAGE("No caption at B5.", pOtherCaptionB5);

        ScDocument aClipDoc2(SCDOCMODE_CLIP);
@@ -5451,7 +5451,7 @@ void Test::testNoteLifeCycle()
        pasteFromClip( m_pDoc, aPosB5, &aClipDoc2); // should not crash... tdf#104967
        ScPostIt* pNoteB5 = m_pDoc->GetNote(aPosB5);
        CPPUNIT_ASSERT_MESSAGE("Failed to paste cell comment at B5.", pNoteB5);
        const SdrCaptionObj* pCaptionB5 = pNoteB5->GetOrCreateCaption(aPosB5);
        const SdrCaptionObj* pCaptionB5 = pNoteB5->GetOrCreateCaption(aPosB5).get();
        CPPUNIT_ASSERT_MESSAGE("No caption at pasted B5.", pCaptionB5);
        // Do not test if  pCaptionB5 != pOtherCaptionB5  because since pDoc2
        // has been closed and the caption been deleted objects *may* be
diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx
index bb68d1c..1b9629c 100644
--- a/sc/source/core/data/documen3.cxx
+++ b/sc/source/core/data/documen3.cxx
@@ -76,6 +76,7 @@
#include <refupdatecontext.hxx>
#include <scopetools.hxx>
#include <filterentries.hxx>
#include <docsh.hxx>

#include <globalnames.hxx>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
@@ -1093,7 +1094,7 @@ void ScDocument::UpdateReference(
    // After moving, no clipboard move ref-updates are possible
    if (rCxt.meMode != URM_COPY && IsClipboardSource())
    {
        ScDocument* pClipDoc = ScModule::GetClipDoc();
        ScDocument* pClipDoc = static_cast<ScDocShell*>(mpShell)->GetClipDoc();
        if (pClipDoc)
            pClipDoc->GetClipParam().mbCutMode = false;
    }
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 32f1669..3f08868 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -99,6 +99,7 @@
#include <tokenarray.hxx>
#include <tokenstringcontext.hxx>
#include <compressedarray.hxx>
#include <docsh.hxx>

#include <formula/vectortoken.hxx>

@@ -2183,7 +2184,7 @@ void ScDocument::CopyToClip(const ScClipParam& rClipParam,
    if (!pClipDoc)
    {
        SAL_WARN("sc", "CopyToClip: no ClipDoc");
        pClipDoc = ScModule::GetClipDoc();
        pClipDoc = static_cast<ScDocShell*>(mpShell)->GetClipDoc();
    }

    if (mpShell->GetMedium())
@@ -2283,7 +2284,7 @@ void ScDocument::CopyTabToClip(SCCOL nCol1, SCROW nRow1,
        if (!pClipDoc)
        {
            SAL_WARN("sc", "CopyTabToClip: no ClipDoc");
            pClipDoc = ScModule::GetClipDoc();
            pClipDoc = static_cast<ScDocShell*>(mpShell)->GetClipDoc();
        }

        if (mpShell->GetMedium())
@@ -2570,7 +2571,7 @@ bool ScDocument::IsClipboardSource() const
    if (bIsClip)
        return false;

    ScDocument* pClipDoc = ScModule::GetClipDoc();
    ScDocument* pClipDoc = static_cast<ScDocShell*>(mpShell)->GetClipDoc();
    return pClipDoc && pClipDoc->bIsClip && pClipDoc->mxPoolHelper.is() && mxPoolHelper.is() &&
            mxPoolHelper->GetDocPool() == pClipDoc->mxPoolHelper->GetDocPool();
}
@@ -2807,7 +2808,7 @@ void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMar
    if (!pClipDoc)
    {
        OSL_FAIL("CopyFromClip: no ClipDoc");
        pClipDoc = ScModule::GetClipDoc();
        pClipDoc = static_cast<ScDocShell*>(mpShell)->GetClipDoc();
    }

    if (!pClipDoc->bIsClip || !pClipDoc->GetTableCount())
diff --git a/sc/source/core/data/postit.cxx b/sc/source/core/data/postit.cxx
index c943d03..4629bbd 100644
--- a/sc/source/core/data/postit.cxx
+++ b/sc/source/core/data/postit.cxx
@@ -44,6 +44,7 @@
#include <patattr.hxx>
#include <formulacell.hxx>
#include <drwlayer.hxx>
#include <undocell.hxx>
#include <userdat.hxx>
#include <detfunc.hxx>
#include <editutil.hxx>
@@ -162,12 +163,12 @@ public:
    /** Create a new caption. The caption will not be inserted into the document. */
    explicit            ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, bool bTailFront );
    /** Manipulate an existing caption. */
    explicit            ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const ScCaptionPtr& xCaption );
    explicit            ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const std::shared_ptr< SdrCaptionObj >& pCaption );

    /** Returns the drawing layer page of the sheet contained in maPos. */
    SdrPage*            GetDrawPage();
    /** Returns the caption drawing object. */
    ScCaptionPtr &      GetCaption() { return mxCaption; }
    const std::shared_ptr< SdrCaptionObj >& GetCaption() { return m_pCaption; }

    /** Moves the caption inside the passed rectangle. Uses page area if 0 is passed. */
    void                FitCaptionToRect( const tools::Rectangle* pVisRect = nullptr );
@@ -194,7 +195,7 @@ private:
private:
    ScDocument&         mrDoc;
    ScAddress           maPos;
    ScCaptionPtr        mxCaption;
    std::shared_ptr< SdrCaptionObj > m_pCaption;
    tools::Rectangle           maPageRect;
    tools::Rectangle           maCellRect;
    bool                mbNegPage;
@@ -208,10 +209,10 @@ ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, boo
    CreateCaption( true/*bShown*/, bTailFront );
}

ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const ScCaptionPtr& xCaption ) :
ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const std::shared_ptr< SdrCaptionObj >& pCaption ) :
    mrDoc( rDoc ),
    maPos( rPos ),
    mxCaption( xCaption )
    m_pCaption( pCaption )
{
    Initialize();
}
@@ -234,13 +235,13 @@ void ScCaptionCreator::FitCaptionToRect( const tools::Rectangle* pVisRect )
    const tools::Rectangle& rVisRect = GetVisRect( pVisRect );

    // tail position
    Point aTailPos = mxCaption->GetTailPos();
    Point aTailPos = m_pCaption->GetTailPos();
    aTailPos.setX( ::std::max( ::std::min( aTailPos.X(), rVisRect.Right() ), rVisRect.Left() ) );
    aTailPos.setY( ::std::max( ::std::min( aTailPos.Y(), rVisRect.Bottom() ), rVisRect.Top() ) );
    mxCaption->SetTailPos( aTailPos );
    m_pCaption->SetTailPos( aTailPos );

    // caption rectangle
    tools::Rectangle aCaptRect = mxCaption->GetLogicRect();
    tools::Rectangle aCaptRect = m_pCaption->GetLogicRect();
    Point aCaptPos = aCaptRect.TopLeft();
    // move textbox inside right border of visible area
    aCaptPos.setX( ::std::min< long >( aCaptPos.X(), rVisRect.Right() - aCaptRect.GetWidth() ) );
@@ -252,7 +253,7 @@ void ScCaptionCreator::FitCaptionToRect( const tools::Rectangle* pVisRect )
    aCaptPos.setY( ::std::max< long >( aCaptPos.Y(), rVisRect.Top() ) );
    // update caption
    aCaptRect.SetPos( aCaptPos );
    mxCaption->SetLogicRect( aCaptRect );
    m_pCaption->SetLogicRect( aCaptRect );
}

void ScCaptionCreator::AutoPlaceCaption( const tools::Rectangle* pVisRect )
@@ -260,7 +261,7 @@ void ScCaptionCreator::AutoPlaceCaption( const tools::Rectangle* pVisRect )
    const tools::Rectangle& rVisRect = GetVisRect( pVisRect );

    // caption rectangle
    tools::Rectangle aCaptRect = mxCaption->GetLogicRect();
    tools::Rectangle aCaptRect = m_pCaption->GetLogicRect();
    long nWidth = aCaptRect.GetWidth();
    long nHeight = aCaptRect.GetHeight();

@@ -318,7 +319,7 @@ void ScCaptionCreator::AutoPlaceCaption( const tools::Rectangle* pVisRect )

    // update textbox position in note caption object
    aCaptRect.SetPos( aCaptPos );
    mxCaption->SetLogicRect( aCaptRect );
    m_pCaption->SetLogicRect( aCaptRect );
    FitCaptionToRect( pVisRect );
}

@@ -327,33 +328,33 @@ void ScCaptionCreator::UpdateCaptionPos()
    ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer();

    // update caption position
    const Point& rOldTailPos = mxCaption->GetTailPos();
    const Point& rOldTailPos = m_pCaption->GetTailPos();
    Point aTailPos = CalcTailPos( false );
    if( rOldTailPos != aTailPos )
    {
        // create drawing undo action
        if( pDrawLayer && pDrawLayer->IsRecording() )
            pDrawLayer->AddCalcUndo( new SdrUndoGeoObj( *mxCaption ) );
            pDrawLayer->AddCalcUndo( new SdrUndoGeoObj( *m_pCaption ) );
        // calculate new caption rectangle (#i98141# handle LTR<->RTL switch correctly)
        tools::Rectangle aCaptRect = mxCaption->GetLogicRect();
        tools::Rectangle aCaptRect = m_pCaption->GetLogicRect();
        long nDiffX = (rOldTailPos.X() >= 0) ? (aCaptRect.Left() - rOldTailPos.X()) : (rOldTailPos.X() - aCaptRect.Right());
        if( mbNegPage ) nDiffX = -nDiffX - aCaptRect.GetWidth();
        long nDiffY = aCaptRect.Top() - rOldTailPos.Y();
        aCaptRect.SetPos( aTailPos + Point( nDiffX, nDiffY ) );
        // set new tail position and caption rectangle
        mxCaption->SetTailPos( aTailPos );
        mxCaption->SetLogicRect( aCaptRect );
        m_pCaption->SetTailPos( aTailPos );
        m_pCaption->SetLogicRect( aCaptRect );
        // fit caption into draw page
        FitCaptionToRect();
    }

    // update cell position in caption user data
    ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( mxCaption.get(), maPos.Tab() );
    ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( m_pCaption.get(), maPos.Tab() );
    if( pCaptData && (maPos != pCaptData->maStart) )
    {
        // create drawing undo action
        if( pDrawLayer && pDrawLayer->IsRecording() )
            pDrawLayer->AddCalcUndo( new ScUndoObjData( mxCaption.get(), pCaptData->maStart, pCaptData->maEnd, maPos, pCaptData->maEnd ) );
            pDrawLayer->AddCalcUndo( new ScUndoObjData( m_pCaption.get(), pCaptData->maStart, pCaptData->maEnd, maPos, pCaptData->maEnd ) );
        // set new position
        pCaptData->maStart = maPos;
    }
@@ -375,13 +376,22 @@ void ScCaptionCreator::CreateCaption( bool bShown, bool bTailFront )
    // create the caption drawing object
    tools::Rectangle aTextRect( Point( 0 , 0 ), Size( SC_NOTECAPTION_WIDTH, SC_NOTECAPTION_HEIGHT ) );
    Point aTailPos = CalcTailPos( bTailFront );
    mxCaption.reset(
    m_pCaption.reset(
        new SdrCaptionObj(
            *mrDoc.GetDrawLayer(), // TTTT should ret a ref?
            aTextRect,
            aTailPos));
            aTailPos),
        [](SdrCaptionObj* pCaptionObj){
            SdrPage* pDrawPage(pCaptionObj->getSdrPageFromSdrObject());
            if (pDrawPage)
            {
                pDrawPage->RemoveObject(pCaptionObj->GetOrdNum());
            }
            SdrObject* pObj = pCaptionObj;
            SdrObject::Free(pObj);
    });
    // basic caption settings
    ScCaptionUtil::SetBasicCaptionSettings( *mxCaption, bShown );
    ScCaptionUtil::SetBasicCaptionSettings( *m_pCaption, bShown );
}

void ScCaptionCreator::Initialize()
@@ -405,7 +415,7 @@ public:
    /** Create a new caption object and inserts it into the document. */
    explicit            ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScNoteData& rNoteData );
    /** Manipulate an existing caption. */
    explicit            ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScCaptionPtr& xCaption, bool bShown );
    explicit            ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const std::shared_ptr< SdrCaptionObj >& xCaption, bool bShown );
};

ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScNoteData& rNoteData ) :
@@ -417,340 +427,38 @@ ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& r
    {
        // create the caption drawing object
        CreateCaption( rNoteData.mbShown, false );
        rNoteData.mxCaption = GetCaption();
        OSL_ENSURE( rNoteData.mxCaption, "ScNoteCaptionCreator::ScNoteCaptionCreator - missing caption object" );
        if( rNoteData.mxCaption )
        rNoteData.m_pCaption = GetCaption();
        OSL_ENSURE( rNoteData.m_pCaption, "ScNoteCaptionCreator::ScNoteCaptionCreator - missing caption object" );
        if( rNoteData.m_pCaption )
        {
            // store note position in user data of caption object
            ScCaptionUtil::SetCaptionUserData( *rNoteData.mxCaption, rPos );
            ScCaptionUtil::SetCaptionUserData( *rNoteData.m_pCaption, rPos );
            // insert object into draw page
            rNoteData.mxCaption.insertToDrawPage( *pDrawPage );
            pDrawPage->InsertObject( rNoteData.m_pCaption.get() );
        }
    }
}

ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScCaptionPtr& xCaption, bool bShown ) :
    ScCaptionCreator( rDoc, rPos, xCaption )
ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const std::shared_ptr< SdrCaptionObj >& pCaption, bool bShown ) :
    ScCaptionCreator( rDoc, rPos, pCaption )
{
    SdrPage* pDrawPage = GetDrawPage();
    OSL_ENSURE( pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - no drawing page" );
    OSL_ENSURE( xCaption->getSdrPageFromSdrObject() == pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - wrong drawing page in caption" );
    if( pDrawPage && (xCaption->getSdrPageFromSdrObject() == pDrawPage) )
    OSL_ENSURE( pCaption->getSdrPageFromSdrObject() == pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - wrong drawing page in caption" );
    if( pDrawPage && (pCaption->getSdrPageFromSdrObject() == pDrawPage) )
    {
        // store note position in user data of caption object
        ScCaptionUtil::SetCaptionUserData( *xCaption, rPos );
        ScCaptionUtil::SetCaptionUserData( *pCaption, rPos );
        // basic caption settings
        ScCaptionUtil::SetBasicCaptionSettings( *xCaption, bShown );
        ScCaptionUtil::SetBasicCaptionSettings( *pCaption, bShown );
        // set correct tail position
        xCaption->SetTailPos( CalcTailPos( false ) );
        pCaption->SetTailPos( CalcTailPos( false ) );
    }
}

} // namespace


ScCaptionPtr::ScCaptionPtr() :
    mpHead(nullptr), mpNext(nullptr), mpCaption(nullptr), mbNotOwner(false)
void removeFromDrawPageAndFree( const std::shared_ptr< SdrCaptionObj >& pCaption, bool bIgnoreUndo = false )
{
}

ScCaptionPtr::ScCaptionPtr( SdrCaptionObj* p ) :
    mpHead(nullptr), mpNext(nullptr), mpCaption(p), mbNotOwner(false)
{
    if (p)
    {
        newHead();
    }
}

ScCaptionPtr::ScCaptionPtr( const ScCaptionPtr& r ) :
    mpHead(r.mpHead), mpCaption(r.mpCaption), mbNotOwner(false)
{
    if (r.mpCaption)
    {
        assert(r.mpHead);
        r.incRef();
        // Insert into list.
        mpNext = r.mpNext;
        r.mpNext = this;
    }
    else
    {
        assert(!r.mpHead);
        mpNext = nullptr;
    }
}

ScCaptionPtr::ScCaptionPtr( ScCaptionPtr&& r ) :
    mpHead(r.mpHead), mpNext(r.mpNext), mpCaption(r.mpCaption), mbNotOwner(false)
{
    r.replaceInList( this );
    r.mpCaption = nullptr;
    r.mbNotOwner = false;
}

ScCaptionPtr& ScCaptionPtr::operator=( ScCaptionPtr&& r )
{
    assert(this != &r);

    mpHead = r.mpHead;
    mpNext = r.mpNext;
    mpCaption = r.mpCaption;
    mbNotOwner = r.mbNotOwner;

    r.replaceInList( this );
    r.mpCaption = nullptr;
    r.mbNotOwner = false;

    return *this;
}

ScCaptionPtr& ScCaptionPtr::operator=( const ScCaptionPtr& r )
{
    if (this == &r)
        return *this;

    if (mpCaption == r.mpCaption)
    {
        // Two lists for the same caption is bad.
        assert(!mpCaption || mpHead == r.mpHead);
        assert(!mpCaption);     // assigning same caption pointer within same list is weird
        // Nullptr captions are not inserted to the list, so nothing to do here
        // if both are.
        return *this;
    }

    // Let's find some weird usage.
    // Assigning without head doesn't make sense unless it is a nullptr caption.
    assert(r.mpHead || !r.mpCaption);
    // A nullptr caption must not be in a list and thus not have a head.
    assert(!r.mpHead || r.mpCaption);
    // Same captions were caught above, so here different heads must be present.
    assert(r.mpHead != mpHead);

    r.incRef();
    decRefAndDestroy();
    removeFromList();

    mpCaption = r.mpCaption;
    mbNotOwner = r.mbNotOwner;
    // That head is this' master.
    mpHead = r.mpHead;
    // Insert into list.
    mpNext = r.mpNext;
    r.mpNext = this;

    return *this;
}

void ScCaptionPtr::setNotOwner()
{
    mbNotOwner = true;
}

ScCaptionPtr::Head::Head( ScCaptionPtr* p ) :
    mpFirst(p), mnRefs(1)
{
}

void ScCaptionPtr::newHead()
{
    assert(!mpHead);
    mpHead = new Head(this);
}

void ScCaptionPtr::replaceInList( ScCaptionPtr* pNew )
{
    if (!mpHead && !mpNext)
        return;

    assert(mpHead);
    assert(mpCaption == pNew->mpCaption);

    ScCaptionPtr* pThat = mpHead->mpFirst;
    while (pThat && pThat != this && pThat->mpNext != this)
    {
        pThat = pThat->mpNext;
    }
    if (pThat && pThat != this)
    {
        assert(pThat->mpNext == this);
        pThat->mpNext = pNew;
    }
    pNew->mpNext = mpNext;
    if (mpHead->mpFirst == this)
        mpHead->mpFirst = pNew;

    mpHead = nullptr;
    mpNext = nullptr;
}

void ScCaptionPtr::removeFromList()
{
    if (!mpHead && !mpNext && !mpCaption)
        return;

#if OSL_DEBUG_LEVEL > 0
    oslInterlockedCount nCount = 0;
#endif
    ScCaptionPtr* pThat = (mpHead ? mpHead->mpFirst : nullptr);
    while (pThat && pThat != this && pThat->mpNext != this)
    {
        // Use the walk to check consistency on the fly.
        assert(pThat->mpHead == mpHead);            // all belong to the same
        assert(pThat->mpHead || !pThat->mpNext);    // next without head is bad
        assert(pThat->mpCaption == mpCaption);
        pThat = pThat->mpNext;
#if OSL_DEBUG_LEVEL > 0
        ++nCount;
#endif
    }
    assert(pThat || !mpHead);   // not found only if this was standalone
    if (pThat)
    {
        if (pThat != this)
        {
#if OSL_DEBUG_LEVEL > 0
            // The while loop above was not executed, and for this
            // (pThat->mpNext) the loop below won't either.
            ++nCount;
#endif
            pThat->mpNext = mpNext;
        }
#if OSL_DEBUG_LEVEL > 0
        do
        {
            assert(pThat->mpHead == mpHead);            // all belong to the same
            assert(pThat->mpHead || !pThat->mpNext);    // next without head is bad
            assert(pThat->mpCaption == mpCaption);
            ++nCount;
        }
        while ((pThat = pThat->mpNext) != nullptr);
#endif
    }
#if OSL_DEBUG_LEVEL > 0
    // If part of a list then refs were already decremented.
    assert(nCount == (mpHead ? mpHead->mnRefs + 1 : 0));
#endif
    if (mpHead && mpHead->mpFirst == this)
    {
        if (mpNext)
            mpHead->mpFirst = mpNext;
        else
        {
            // The only one destroys also head.
            assert(mpHead->mnRefs == 0);    // cough
            delete mpHead;                  // DEAD now
        }
    }
    mpHead = nullptr;
    mpNext = nullptr;
}

void ScCaptionPtr::reset( SdrCaptionObj* p )
{
    assert(!p || p != mpCaption);
#if OSL_DEBUG_LEVEL > 0
    if (p)
    {
        // Check if we end up with a duplicated management in this list.
        ScCaptionPtr* pThat = (mpHead ? mpHead->mpFirst : nullptr);
        while (pThat)
        {
            assert(pThat->mpCaption != p);
            pThat = pThat->mpNext;
        }
    }
#endif
    decRefAndDestroy();
    removeFromList();
    mpCaption = p;
    mbNotOwner = false;
    if (p)
    {
        newHead();
    }
}

ScCaptionPtr::~ScCaptionPtr()
{
    decRefAndDestroy();
    removeFromList();
}

oslInterlockedCount ScCaptionPtr::getRefs() const
{
    return mpHead ? mpHead->mnRefs : 0;
}

void ScCaptionPtr::incRef() const
{
    if (mpHead)
        osl_atomic_increment(&mpHead->mnRefs);
}

bool ScCaptionPtr::decRef() const
{
    return mpHead && mpHead->mnRefs > 0 && !osl_atomic_decrement(&mpHead->mnRefs);
}

void ScCaptionPtr::decRefAndDestroy()
{
    if (decRef())
    {
        assert(mpHead->mpFirst == this);    // this must be one and only one
        assert(!mpNext);                    // this must be one and only one
        assert(mpCaption);

#if 0
        // Quick workaround for when there are still cases where the caption
        // pointer is dangling
        mpCaption = nullptr;
        mbNotOwner = false;
#else
        // Destroying Draw Undo and some other delete the SdrObject, don't
        // attempt that twice.
        if (mbNotOwner)
        {
            mpCaption = nullptr;
            mbNotOwner = false;
        }
        else
        {
            removeFromDrawPageAndFree( true );  // ignoring Undo
            if (mpCaption)
            {
                // There's no draw page associated so removeFromDrawPageAndFree()
                // didn't do anything, but still we want to delete the caption
                // object. release()/dissolve() also resets mpCaption.
                SdrObject* pObj = release();
                SdrObject::Free( pObj );
            }
        }
#endif
        delete mpHead;
        mpHead = nullptr;
    }
}

void ScCaptionPtr::insertToDrawPage( SdrPage& rDrawPage )
{
    assert(mpHead && mpCaption);

    rDrawPage.InsertObject( mpCaption );
}

void ScCaptionPtr::removeFromDrawPage( SdrPage& rDrawPage )
{
    assert(mpHead && mpCaption);
    SdrObject* pObj = rDrawPage.RemoveObject( mpCaption->GetOrdNum() );
    assert(pObj == mpCaption); (void)pObj;
}

void ScCaptionPtr::removeFromDrawPageAndFree( bool bIgnoreUndo )
{
    assert(mpHead && mpCaption);
    SdrPage* pDrawPage(mpCaption->getSdrPageFromSdrObject());
    SdrPage* pDrawPage(pCaption->getSdrPageFromSdrObject());
    SAL_WARN_IF( !pDrawPage, "sc.core", "ScCaptionPtr::removeFromDrawPageAndFree - object without drawing page");
    if (pDrawPage)
    {
@@ -758,64 +466,19 @@ void ScCaptionPtr::removeFromDrawPageAndFree( bool bIgnoreUndo )
        bool bRecording = false;
        if (!bIgnoreUndo)
        {
            ScDrawLayer* pDrawLayer(dynamic_cast< ScDrawLayer* >(&mpCaption->getSdrModelFromSdrObject()));
            ScDrawLayer* pDrawLayer(dynamic_cast< ScDrawLayer* >(&pCaption->getSdrModelFromSdrObject()));
            SAL_WARN_IF( !pDrawLayer, "sc.core", "ScCaptionPtr::removeFromDrawPageAndFree - object without drawing layer");
            // create drawing undo action (before removing the object to have valid draw page in undo action)
            bRecording = (pDrawLayer && pDrawLayer->IsRecording());
            if (bRecording)
                pDrawLayer->AddCalcUndo( new SdrUndoDelObj( *mpCaption ));
                pDrawLayer->AddCalcUndo( new ScUndoDelSdrCaptionObj( pCaption ));
        }
        // remove the object from the drawing page, delete if undo is disabled
        removeFromDrawPage( *pDrawPage );
        // If called from outside mnRefs must be 1 to delete. If called from
        // decRefAndDestroy() mnRefs is already 0.
        if (!bRecording && getRefs() <= 1)
        {
            SdrObject* pObj = release();
            SdrObject::Free( pObj );
        }
        pDrawPage->RemoveObject( pCaption->GetOrdNum() );
    }
}

SdrCaptionObj* ScCaptionPtr::release()
{
    SdrCaptionObj* pTmp = mpCaption;
    dissolve();
    return pTmp;
}

void ScCaptionPtr::forget()
{
    decRef();
    removeFromList();
    mpCaption = nullptr;
    mbNotOwner = false;
}

void ScCaptionPtr::dissolve()
{
    ScCaptionPtr::Head* pHead = mpHead;
    ScCaptionPtr* pThat = (mpHead ? mpHead->mpFirst : this);
    while (pThat)
    {
        assert(!pThat->mpNext || pThat->mpHead);    // next without head is bad
        assert(pThat->mpHead == pHead);             // same head required within one list
        ScCaptionPtr* p = pThat->mpNext;
        pThat->clear();
        pThat = p;
    }
    assert(!mpHead && !mpNext && !mpCaption);       // should had been cleared during list walk
    delete pHead;
}

void ScCaptionPtr::clear()
{
    mpHead = nullptr;
    mpNext = nullptr;
    mpCaption = nullptr;
    mbNotOwner = false;
}

} // namespace

struct ScCaptionInitData
{
@@ -851,7 +514,7 @@ ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, sal_uInt32 nPostItI
{
    mnPostItId = nPostItId == 0 ? mnLastPostItId++ : nPostItId;
    AutoStamp();
    CreateCaption( rPos );
    CreateCaption( rPos, nullptr );
}

ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, const ScPostIt& rNote, sal_uInt32 nPostItId ) :
@@ -859,8 +522,8 @@ ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, const ScPostIt& rNo
    maNoteData( rNote.maNoteData )
{
    mnPostItId = nPostItId == 0 ? mnLastPostItId++ : nPostItId;
    maNoteData.mxCaption.reset(nullptr);
    CreateCaption( rPos, rNote.maNoteData.mxCaption.get() );
    maNoteData.m_pCaption.reset();
    CreateCaption( rPos, rNote.maNoteData.m_pCaption );
}

ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, const ScNoteData& rNoteData, bool bAlwaysCreateCaption, sal_uInt32 nPostItId ) :
@@ -901,8 +564,8 @@ void ScPostIt::AutoStamp()

const OutlinerParaObject* ScPostIt::GetOutlinerObject() const
{
    if( maNoteData.mxCaption )
        return maNoteData.mxCaption->GetOutlinerParaObject();
    if( maNoteData.m_pCaption )
        return maNoteData.m_pCaption->GetOutlinerParaObject();
    if( maNoteData.mxInitData.get() )
        return maNoteData.mxInitData->mxOutlinerObj.get();
    return nullptr;
@@ -947,14 +610,14 @@ bool ScPostIt::HasMultiLineText() const
void ScPostIt::SetText( const ScAddress& rPos, const OUString& rText )
{
    CreateCaptionFromInitData( rPos );
    if( maNoteData.mxCaption )
        maNoteData.mxCaption->SetText( rText );
    if( maNoteData.m_pCaption )
        maNoteData.m_pCaption->SetText( rText );
}

SdrCaptionObj* ScPostIt::GetOrCreateCaption( const ScAddress& rPos ) const
const std::shared_ptr< SdrCaptionObj>& ScPostIt::GetOrCreateCaption( const ScAddress& rPos ) const
{
    CreateCaptionFromInitData( rPos );
    return maNoteData.mxCaption.get();
    return maNoteData.m_pCaption;
}

void ScPostIt::ForgetCaption( bool bPreserveData )
@@ -974,13 +637,13 @@ void ScPostIt::ForgetCaption( bool bPreserveData )
        pInitData->maSimpleText = GetText();

        maNoteData.mxInitData.reset(pInitData);
        maNoteData.mxCaption.forget();
        maNoteData.m_pCaption.reset();
    }
    else
    {
        /*  This function is used in undo actions to give up the responsibility for
            the caption object which is handled by separate drawing undo actions. */
        maNoteData.mxCaption.forget();
        maNoteData.m_pCaption.reset();
        maNoteData.mxInitData.reset();
    }
}
@@ -990,23 +653,23 @@ void ScPostIt::ShowCaption( const ScAddress& rPos, bool bShow )
    CreateCaptionFromInitData( rPos );
    // no separate drawing undo needed, handled completely inside ScUndoShowHideNote
    maNoteData.mbShown = bShow;
    if( maNoteData.mxCaption )
        ScCaptionUtil::SetCaptionLayer( *maNoteData.mxCaption, bShow );
    if( maNoteData.m_pCaption )
        ScCaptionUtil::SetCaptionLayer( *maNoteData.m_pCaption, bShow );
}

void ScPostIt::ShowCaptionTemp( const ScAddress& rPos, bool bShow )
{
    CreateCaptionFromInitData( rPos );
    if( maNoteData.mxCaption )
        ScCaptionUtil::SetCaptionLayer( *maNoteData.mxCaption, maNoteData.mbShown || bShow );
    if( maNoteData.m_pCaption )
        ScCaptionUtil::SetCaptionLayer( *maNoteData.m_pCaption, maNoteData.mbShown || bShow );
}

void ScPostIt::UpdateCaptionPos( const ScAddress& rPos )
{
    CreateCaptionFromInitData( rPos );
    if( maNoteData.mxCaption )
    if( maNoteData.m_pCaption )
    {
        ScCaptionCreator aCreator( mrDoc, rPos, maNoteData.mxCaption );
        ScCaptionCreator aCreator( mrDoc, rPos, maNoteData.m_pCaption );
        aCreator.UpdateCaptionPos();
    }
}
@@ -1017,7 +680,7 @@ void ScPostIt::CreateCaptionFromInitData( const ScAddress& rPos ) const
{
    // Captions are not created in Undo documents and only rarely in Clipboard,
    // but otherwise we need caption or initial data.
    assert((maNoteData.mxCaption || maNoteData.mxInitData.get()) || mrDoc.IsUndo() || mrDoc.IsClipboard());
    assert((maNoteData.m_pCaption || maNoteData.mxInitData.get()) || mrDoc.IsUndo() || mrDoc.IsClipboard());
    if( maNoteData.mxInitData.get() )
    {
        /*  This function is called from ScPostIt::Clone() when copying cells
@@ -1027,22 +690,22 @@ void ScPostIt::CreateCaptionFromInitData( const ScAddress& rPos ) const
            been created already. However, for clipboard in case the
            originating document was destructed a new caption has to be
            created. */
        OSL_ENSURE( !mrDoc.IsUndo() && (!mrDoc.IsClipboard() || !maNoteData.mxCaption),
        OSL_ENSURE( !mrDoc.IsUndo() && (!mrDoc.IsClipboard() || !maNoteData.m_pCaption),
                "ScPostIt::CreateCaptionFromInitData - note caption should not be created in undo/clip documents" );

        /*  #i104915# Never try to create notes in Undo document, leads to
            crash due to missing document members (e.g. row height array). */
        if( !maNoteData.mxCaption && !mrDoc.IsUndo() )
        if( !maNoteData.m_pCaption && !mrDoc.IsUndo() )
        {
            if (mrDoc.IsClipboard())
                mrDoc.InitDrawLayer();  // ensure there is a drawing layer

            // ScNoteCaptionCreator c'tor creates the caption and inserts it into the document and maNoteData
            ScNoteCaptionCreator aCreator( mrDoc, rPos, maNoteData );
            if( maNoteData.mxCaption )
            if( maNoteData.m_pCaption )
            {
                // Prevent triple change broadcasts of the same object.
                SdrDelayBroadcastObjectChange aDelayChange( *maNoteData.mxCaption);
                SdrDelayBroadcastObjectChange aDelayChange( *maNoteData.m_pCaption);

                ScCaptionInitData& rInitData = *maNoteData.mxInitData;

@@ -1050,22 +713,22 @@ void ScPostIt::CreateCaptionFromInitData( const ScAddress& rPos ) const
                OSL_ENSURE( rInitData.mxOutlinerObj.get() || !rInitData.maSimpleText.isEmpty(),
                    "ScPostIt::CreateCaptionFromInitData - need either outliner para object or simple text" );
                if( rInitData.mxOutlinerObj.get() )
                    maNoteData.mxCaption->SetOutlinerParaObject( rInitData.mxOutlinerObj.release() );
                    maNoteData.m_pCaption->SetOutlinerParaObject( rInitData.mxOutlinerObj.release() );
                else
                    maNoteData.mxCaption->SetText( rInitData.maSimpleText );
                    maNoteData.m_pCaption->SetText( rInitData.maSimpleText );

                // copy all items or set default items; reset shadow items
                ScCaptionUtil::SetDefaultItems( *maNoteData.mxCaption, mrDoc );
                ScCaptionUtil::SetDefaultItems( *maNoteData.m_pCaption, mrDoc );
                if( rInitData.mxItemSet.get() )
                    ScCaptionUtil::SetCaptionItems( *maNoteData.mxCaption, *rInitData.mxItemSet );
                    ScCaptionUtil::SetCaptionItems( *maNoteData.m_pCaption, *rInitData.mxItemSet );

                // set position and size of the caption object
                if( rInitData.mbDefaultPosSize )
                {
                    // set other items and fit caption size to text
                    maNoteData.mxCaption->SetMergedItem( makeSdrTextMinFrameWidthItem( SC_NOTECAPTION_WIDTH ) );
                    maNoteData.mxCaption->SetMergedItem( makeSdrTextMaxFrameWidthItem( SC_NOTECAPTION_MAXWIDTH_TEMP ) );
                    maNoteData.mxCaption->AdjustTextFrameWidthAndHeight();
                    maNoteData.m_pCaption->SetMergedItem( makeSdrTextMinFrameWidthItem( SC_NOTECAPTION_WIDTH ) );
                    maNoteData.m_pCaption->SetMergedItem( makeSdrTextMaxFrameWidthItem( SC_NOTECAPTION_MAXWIDTH_TEMP ) );
                    maNoteData.m_pCaption->AdjustTextFrameWidthAndHeight();
                    aCreator.AutoPlaceCaption();
                }
                else
@@ -1075,7 +738,7 @@ void ScPostIt::CreateCaptionFromInitData( const ScAddress& rPos ) const
                    long nPosX = bNegPage ? (aCellRect.Left() - rInitData.maCaptionOffset.X()) : (aCellRect.Right() + rInitData.maCaptionOffset.X());
                    long nPosY = aCellRect.Top() + rInitData.maCaptionOffset.Y();
                    tools::Rectangle aCaptRect( Point( nPosX, nPosY ), rInitData.maCaptionSize );
                    maNoteData.mxCaption->SetLogicRect( aCaptRect );
                    maNoteData.m_pCaption->SetLogicRect( aCaptRect );
                    aCreator.FitCaptionToRect();
                }
            }
@@ -1085,10 +748,10 @@ void ScPostIt::CreateCaptionFromInitData( const ScAddress& rPos ) const
    }
}

void ScPostIt::CreateCaption( const ScAddress& rPos, const SdrCaptionObj* pCaption )
void ScPostIt::CreateCaption( const ScAddress& rPos, const std::shared_ptr< SdrCaptionObj >& pCaption )
{
    OSL_ENSURE( !maNoteData.mxCaption, "ScPostIt::CreateCaption - unexpected caption object found" );
    maNoteData.mxCaption.reset(nullptr);
    OSL_ENSURE( !maNoteData.m_pCaption, "ScPostIt::CreateCaption - unexpected caption object found" );
    maNoteData.m_pCaption.reset();

    /*  #i104915# Never try to create notes in Undo document, leads to
        crash due to missing document members (e.g. row height array). */
@@ -1102,40 +765,40 @@ void ScPostIt::CreateCaption( const ScAddress& rPos, const SdrCaptionObj* pCapti

    // ScNoteCaptionCreator c'tor creates the caption and inserts it into the document and maNoteData
    ScNoteCaptionCreator aCreator( mrDoc, rPos, maNoteData );
    if( maNoteData.mxCaption )
    if( maNoteData.m_pCaption )
    {
        // clone settings of passed caption
        if( pCaption )
        {
            // copy edit text object (object must be inserted into page already)
            if( OutlinerParaObject* pOPO = pCaption->GetOutlinerParaObject() )
                maNoteData.mxCaption->SetOutlinerParaObject( new OutlinerParaObject( *pOPO ) );
                maNoteData.m_pCaption->SetOutlinerParaObject( new OutlinerParaObject( *pOPO ) );
            // copy formatting items (after text has been copied to apply font formatting)
            maNoteData.mxCaption->SetMergedItemSetAndBroadcast( pCaption->GetMergedItemSet() );
            maNoteData.m_pCaption->SetMergedItemSetAndBroadcast( pCaption->GetMergedItemSet() );
            // move textbox position relative to new cell, copy textbox size
            tools::Rectangle aCaptRect = pCaption->GetLogicRect();
            Point aDist = maNoteData.mxCaption->GetTailPos() - pCaption->GetTailPos();
            Point aDist = maNoteData.m_pCaption->GetTailPos() - pCaption->GetTailPos();
            aCaptRect.Move( aDist.X(), aDist.Y() );
            maNoteData.mxCaption->SetLogicRect( aCaptRect );
            maNoteData.m_pCaption->SetLogicRect( aCaptRect );
            aCreator.FitCaptionToRect();
        }
        else
        {
            // set default formatting and default position
            ScCaptionUtil::SetDefaultItems( *maNoteData.mxCaption, mrDoc );
            ScCaptionUtil::SetDefaultItems( *maNoteData.m_pCaption, mrDoc );
            aCreator.AutoPlaceCaption();
        }

        // create undo action
        if( ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer() )
            if( pDrawLayer->IsRecording() )
                pDrawLayer->AddCalcUndo( new SdrUndoNewObj( *maNoteData.mxCaption ) );
                pDrawLayer->AddCalcUndo( new ScUndoNewSdrCaptionObj( maNoteData.m_pCaption ) );
    }
}

void ScPostIt::RemoveCaption()
{
    if (!maNoteData.mxCaption)
    if (!maNoteData.m_pCaption)
        return;

    /*  Remove caption object only, if this note is its owner (e.g. notes in
@@ -1143,28 +806,19 @@ void ScPostIt::RemoveCaption()
        them from drawing layer here). */
    // TTTT maybe no longer needed - can that still happen?
    ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer();
    if (pDrawLayer == &maNoteData.mxCaption->getSdrModelFromSdrObject())
        maNoteData.mxCaption.removeFromDrawPageAndFree();
    if (pDrawLayer == &maNoteData.m_pCaption->getSdrModelFromSdrObject())
        removeFromDrawPageAndFree(maNoteData.m_pCaption);

    SAL_INFO("sc.core","ScPostIt::RemoveCaption - refs: " << maNoteData.mxCaption.getRefs() <<
            "  IsUndo: " << mrDoc.IsUndo() << "  IsClip: " << mrDoc.IsClipboard() <<
            "  Dtor: " << mrDoc.IsInDtorClear());

    // Forget the caption object if removeFromDrawPageAndFree() did not free it.
    if (maNoteData.mxCaption)
    {
        SAL_INFO("sc.core","ScPostIt::RemoveCaption - forgetting one ref");
        maNoteData.mxCaption.forget();
    }
    maNoteData.m_pCaption.reset();
}

ScCaptionPtr ScNoteUtil::CreateTempCaption(
std::shared_ptr< SdrCaptionObj > ScNoteUtil::CreateTempCaption(
        ScDocument& rDoc, const ScAddress& rPos, SdrPage& rDrawPage,
        const OUString& rUserText, const tools::Rectangle& rVisRect, bool bTailFront )
{
    OUStringBuffer aBuffer( rUserText );
    // add plain text of invisible (!) cell note (no formatting etc.)
    SdrCaptionObj* pNoteCaption = nullptr;
    std::shared_ptr< SdrCaptionObj > pNoteCaption = nullptr;
    const ScPostIt* pNote = rDoc.GetNote( rPos );
    if( pNote && !pNote->IsCaptionShown() )
    {
@@ -1175,7 +829,7 @@ ScCaptionPtr ScNoteUtil::CreateTempCaption(

    // create a caption if any text exists
    if( !pNoteCaption && aBuffer.isEmpty() )
        return ScCaptionPtr();
        return std::shared_ptr< SdrCaptionObj >();

    // prepare visible rectangle (add default distance to all borders)
    tools::Rectangle aVisRect(
@@ -1188,7 +842,7 @@ ScCaptionPtr ScNoteUtil::CreateTempCaption(
    ScCaptionCreator aCreator( rDoc, rPos, bTailFront );

    // insert caption into page (needed to set caption text)
    aCreator.GetCaption().insertToDrawPage( rDrawPage );
    rDrawPage.InsertObject( aCreator.GetCaption().get() );

    SdrCaptionObj* pCaption = aCreator.GetCaption().get();  // just for ease of use

@@ -1227,14 +881,22 @@ ScPostIt* ScNoteUtil::CreateNoteFromCaption(
        ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj* pCaption )
{
    ScNoteData aNoteData( true/*bShown*/ );
    aNoteData.mxCaption.reset( pCaption );
    aNoteData.m_pCaption.reset(pCaption, [](SdrCaptionObj* pCaptionObj) {
        SdrPage* pDrawPage(pCaptionObj->getSdrPageFromSdrObject());
        if (pDrawPage)
        {
            pDrawPage->RemoveObject(pCaptionObj->GetOrdNum());
        }
        SdrObject* pObj = pCaptionObj;
        SdrObject::Free(pObj);
    });
    ScPostIt* pNote = new ScPostIt( rDoc, rPos, aNoteData, false );
    pNote->AutoStamp();

    rDoc.SetNote(rPos, pNote);

    // ScNoteCaptionCreator c'tor updates the caption object to be part of a note
    ScNoteCaptionCreator aCreator( rDoc, rPos, aNoteData.mxCaption, true/*bShown*/ );
    ScNoteCaptionCreator aCreator( rDoc, rPos, aNoteData.m_pCaption, true/*bShown*/ );

    return pNote;
}
diff --git a/sc/source/core/tool/detfunc.cxx b/sc/source/core/tool/detfunc.cxx
index 0703baa..a356ee3 100644
--- a/sc/source/core/tool/detfunc.cxx
+++ b/sc/source/core/tool/detfunc.cxx
@@ -1425,7 +1425,7 @@ void ScDetectiveFunc::UpdateAllComments( ScDocument& rDoc )
                {
                    ScPostIt* pNote = rDoc.GetNote( pData->maStart );
                    // caption should exist, we iterate over drawing objects...
                    OSL_ENSURE( pNote && (pNote->GetCaption() == pObject), "ScDetectiveFunc::UpdateAllComments - invalid cell note" );
                    OSL_ENSURE( pNote && (pNote->GetCaption().get() == pObject), "ScDetectiveFunc::UpdateAllComments - invalid cell note" );
                    if( pNote )
                    {
                        ScCommentData aData( rDoc, pModel );
diff --git a/sc/source/filter/excel/xeescher.cxx b/sc/source/filter/excel/xeescher.cxx
index 4c372869..c2e9aba 100644
--- a/sc/source/filter/excel/xeescher.cxx
+++ b/sc/source/filter/excel/xeescher.cxx
@@ -1196,7 +1196,7 @@ XclExpNote::XclExpNote(const XclExpRoot& rRoot, const ScAddress& rScPos,
            // TODO: additional text
            if( pScNote )
            {
                if( SdrCaptionObj* pCaption = pScNote->GetOrCreateCaption( maScPos ) )
                if( SdrCaptionObj* pCaption = pScNote->GetOrCreateCaption( maScPos ).get() )
                {
                    lcl_GetFromTo( rRoot, pCaption->GetLogicRect(), maScPos.Tab(), maCommentFrom, maCommentTo );
                    if( const OutlinerParaObject* pOPO = pCaption->GetOutlinerParaObject() )
diff --git a/sc/source/filter/xml/xmlexprt.cxx b/sc/source/filter/xml/xmlexprt.cxx
index 6e5c2b4..bcfe73f 100644
--- a/sc/source/filter/xml/xmlexprt.cxx
+++ b/sc/source/filter/xml/xmlexprt.cxx
@@ -2406,7 +2406,7 @@ void ScXMLExport::ExportAutoStyles_()
                    OSL_ENSURE( pNote, "note not found" );
                    if (pNote)
                    {
                        SdrCaptionObj* pDrawObj = pNote->GetOrCreateCaption( aPos );
                        std::shared_ptr< SdrCaptionObj > pDrawObj = pNote->GetOrCreateCaption( aPos );
                        // all uno shapes are created anyway in CollectSharedData
                        uno::Reference<beans::XPropertySet> xShapeProperties( pDrawObj->getUnoShape(), uno::UNO_QUERY );
                        if (xShapeProperties.is())
@@ -2450,7 +2450,7 @@ void ScXMLExport::ExportAutoStyles_()
                    OSL_ENSURE( pNote, "note not found" );
                    if (pNote)
                    {
                        SdrCaptionObj* pDrawObj = pNote->GetOrCreateCaption( aPos );
                        std::shared_ptr< SdrCaptionObj > pDrawObj = pNote->GetOrCreateCaption( aPos );
                        uno::Reference<container::XEnumerationAccess> xCellText(pDrawObj->getUnoShape(), uno::UNO_QUERY);
                        uno::Reference<beans::XPropertySet> xParaProp(
                            lcl_GetEnumerated( xCellText, aNoteParaIter->maSelection.nStartPara ), uno::UNO_QUERY );
@@ -2484,7 +2484,7 @@ void ScXMLExport::ExportAutoStyles_()
                    OSL_ENSURE( pNote, "note not found" );
                    if (pNote)
                    {
                        SdrCaptionObj* pDrawObj = pNote->GetOrCreateCaption( aPos );
                        std::shared_ptr< SdrCaptionObj > pDrawObj = pNote->GetOrCreateCaption( aPos );
                        uno::Reference<text::XSimpleText> xCellText(pDrawObj->getUnoShape(), uno::UNO_QUERY);
                        uno::Reference<beans::XPropertySet> xCursorProp(xCellText->createTextCursor(), uno::UNO_QUERY);
                        ScDrawTextCursor* pCursor = ScDrawTextCursor::getImplementation( xCursorProp );
@@ -3617,7 +3617,7 @@ void ScXMLExport::exportAnnotationMeta( const uno::Reference < drawing::XShape >
        // TODO : notes
        //is it still useful, as this call back is only called from ScXMLExport::WriteAnnotation
        // and should be in sync with pCurrentCell
        SdrCaptionObj* pNoteCaption = pNote->GetOrCreateCaption(pCurrentCell->maCellAddress);
        std::shared_ptr< SdrCaptionObj > pNoteCaption = pNote->GetOrCreateCaption(pCurrentCell->maCellAddress);
        uno::Reference<drawing::XShape> xCurrentShape( pNoteCaption->getUnoShape(), uno::UNO_QUERY );
        if (xCurrentShape.get()!=xShape.get())
            return;
@@ -3674,7 +3674,7 @@ void ScXMLExport::WriteAnnotation(ScMyCell& rMyCell)

        pCurrentCell = &rMyCell;

        SdrCaptionObj* pNoteCaption = pNote->GetOrCreateCaption(rMyCell.maCellAddress);
        std::shared_ptr< SdrCaptionObj > pNoteCaption = pNote->GetOrCreateCaption(rMyCell.maCellAddress);
        if (pNoteCaption)
        {
            uno::Reference<drawing::XShape> xShape( pNoteCaption->getUnoShape(), uno::UNO_QUERY );
diff --git a/sc/source/ui/app/scmod.cxx b/sc/source/ui/app/scmod.cxx
index c0f8a33..687ced1 100644
--- a/sc/source/ui/app/scmod.cxx
+++ b/sc/source/ui/app/scmod.cxx
@@ -659,34 +659,6 @@ void ScModule::SetDragJump(
    m_pDragData->aJumpText = rText;
}

ScDocument* ScModule::GetClipDoc()
{
    // called from document
    SfxViewFrame* pViewFrame = nullptr;
    ScTabViewShell* pViewShell = nullptr;
    css::uno::Reference<css::datatransfer::XTransferable2> xTransferable;

    if ((pViewShell = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current())))
        xTransferable.set(pViewShell->GetClipData());
    else if ((pViewShell = dynamic_cast<ScTabViewShell*>(SfxViewShell::GetFirst())))
        xTransferable.set(pViewShell->GetClipData());
    else if ((pViewFrame = SfxViewFrame::GetFirst()))
    {
        css::uno::Reference<css::datatransfer::clipboard::XClipboard> xClipboard =
            pViewFrame->GetWindow().GetClipboard();
        xTransferable.set(xClipboard.is() ? xClipboard->getContents() : nullptr, css::uno::UNO_QUERY);
    }

    const ScTransferObj* pObj = ScTransferObj::GetOwnClipboard(xTransferable);
    if (pObj)
    {
        ScDocument* pDoc = pObj->GetDocument();
        assert((!pDoc || pDoc->IsClipboard()) && "Document is not clipboard, how can that be?");
        return pDoc;
    }

    return nullptr;
}

void ScModule::SetSelectionTransfer( ScSelectionTransferObj* pNew )
{
diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx
index 3908a1a..518410f 100644
--- a/sc/source/ui/docshell/docfunc.cxx
+++ b/sc/source/ui/docshell/docfunc.cxx
@@ -1206,7 +1206,7 @@ bool ScDocFunc::ShowNote( const ScAddress& rPos, bool bShow )
    if (ScViewData* pViewData = ScDocShell::GetViewData())
    {
        if (ScDrawView* pDrawView = pViewData->GetScDrawView())
            pDrawView->SyncForGrid( pNote->GetCaption());
            pDrawView->SyncForGrid( pNote->GetCaption().get() );
    }

    rDocShell.SetDocumentModified();
@@ -1282,7 +1282,7 @@ void ScDocFunc::ReplaceNote( const ScAddress& rPos, const OUString& rNoteText, c
        }

        // create the undo action
        if( pUndoMgr && (aOldData.mxCaption || aNewData.mxCaption) )
        if( pUndoMgr && (aOldData.m_pCaption || aNewData.m_pCaption) )
            pUndoMgr->AddUndoAction( new ScUndoReplaceNote( rDocShell, rPos, aOldData, aNewData, pDrawLayer->GetCalcUndo().release() ) );

        // repaint cell (to make note marker visible)
diff --git a/sc/source/ui/docshell/docsh.cxx b/sc/source/ui/docshell/docsh.cxx
index b0c10dd..40d6107 100644
--- a/sc/source/ui/docshell/docsh.cxx
+++ b/sc/source/ui/docshell/docsh.cxx
@@ -114,6 +114,7 @@
#include <optsolver.hxx>
#include <sheetdata.hxx>
#include <tabprotection.hxx>
#include <transobj.hxx>
#include <docparam.hxx>
#include "docshimp.hxx"
#include <sizedev.hxx>
@@ -1076,7 +1077,7 @@ void ScDocShell::Notify( SfxBroadcaster&, const SfxHint& rHint )
            // document's drawing layer pages and what not, which otherwise when
            // pasting to another document after this document was destructed would
            // attempt to access non-existing data. Preserve the text data though.
            ScDocument* pClipDoc = ScModule::GetClipDoc();
            ScDocument* pClipDoc = GetClipDoc();
            if (pClipDoc)
                pClipDoc->ClosingClipboardSource();
        }
@@ -2783,6 +2784,36 @@ ScDocFunc *ScDocShell::CreateDocFunc()
    return new ScDocFuncDirect( *this );
}

ScDocument* ScDocShell::GetClipDoc()
{
    css::uno::Reference<css::datatransfer::XTransferable2> xTransferable;

    if (ScTabViewShell* pViewShell = GetBestViewShell())
        xTransferable.set(pViewShell->GetClipData());
    else
    {
        SfxViewFrame* pViewFrame = nullptr;
        css::uno::Reference<css::datatransfer::clipboard::XClipboard> xClipboard;

        if ((pViewFrame = SfxViewFrame::GetFirst(this, false)))
            xClipboard = pViewFrame->GetWindow().GetClipboard();
        else if ((pViewFrame = SfxViewFrame::GetFirst()))
             xClipboard = pViewFrame->GetWindow().GetClipboard();

        xTransferable.set(xClipboard.is() ? xClipboard->getContents() : nullptr, css::uno::UNO_QUERY);
    }

    const ScTransferObj* pObj = ScTransferObj::GetOwnClipboard(xTransferable);
    if (pObj)
    {
        ScDocument* pDoc = pObj->GetDocument();
        assert((!pDoc || pDoc->IsClipboard()) && "Document is not clipboard, how can that be?");
        return pDoc;
    }

    return nullptr;
}

ScDocShell::ScDocShell( const ScDocShell& rShell ) :
    SvRefBase(),
    SotObject(),
diff --git a/sc/source/ui/drawfunc/futext3.cxx b/sc/source/ui/drawfunc/futext3.cxx
index a9e243f..4a00355 100644
--- a/sc/source/ui/drawfunc/futext3.cxx
+++ b/sc/source/ui/drawfunc/futext3.cxx
@@ -68,7 +68,7 @@ void FuText::StopEditMode()
    {
        aNotePos = pCaptData->maStart;
        pNote = rDoc.GetNote( aNotePos );
        OSL_ENSURE( pNote && (pNote->GetCaption() == pObject), "FuText::StopEditMode - missing or invalid cell note" );
        OSL_ENSURE( pNote && (pNote->GetCaption().get() == pObject), "FuText::StopEditMode - missing or invalid cell note" );
    }

    ScDocShell* pDocShell = rViewData.GetDocShell();
@@ -88,7 +88,7 @@ void FuText::StopEditMode()
            /*  Note has been created before editing, if first undo action is
                an insert action. Needed below to decide whether to drop the
                undo if editing a new note has been cancelled. */
            bNewNote = (pCalcUndo->GetActionCount() > 0) && dynamic_cast< SdrUndoNewObj* >(pCalcUndo->GetAction( 0 ));
            bNewNote = (pCalcUndo->GetActionCount() > 0) && dynamic_cast< ScUndoNewSdrCaptionObj* >(pCalcUndo->GetAction( 0 ));

            // create a "insert note" undo action if needed
            if( bNewNote )
diff --git a/sc/source/ui/inc/docsh.hxx b/sc/source/ui/inc/docsh.hxx
index d65b097..6082dee 100644
--- a/sc/source/ui/inc/docsh.hxx
+++ b/sc/source/ui/inc/docsh.hxx
@@ -379,6 +379,8 @@ public:

    ScTabViewShell* GetBestViewShell( bool bOnlyVisible = true );

    ScDocument*   GetClipDoc();

    void            SetDocumentModifiedPending( bool bVal )
                        { m_bDocumentModifiedPending = bVal; }
    bool            IsDocumentModifiedPending() const
diff --git a/sc/source/ui/inc/notemark.hxx b/sc/source/ui/inc/notemark.hxx
index e0e723c..a830531 100644
--- a/sc/source/ui/inc/notemark.hxx
+++ b/sc/source/ui/inc/notemark.hxx
@@ -48,7 +48,7 @@ private:
    tools::Rectangle       m_aRect;
    ScDrawView*     m_pDrawView;
    SdrModel*       m_pModel;
    ScCaptionPtr    m_xObject;
    std::shared_ptr< SdrCaptionObj >    m_xObject;
    bool            m_bVisible;
    DECL_LINK( TimeHdl, Timer*, void );

diff --git a/sc/source/ui/inc/undocell.hxx b/sc/source/ui/inc/undocell.hxx
index 67306e5..695c36f 100644
--- a/sc/source/ui/inc/undocell.hxx
+++ b/sc/source/ui/inc/undocell.hxx
@@ -42,6 +42,51 @@ class CellValues;

}

class ScUndoSdrCaptionObj: public SdrUndoAction
{
protected:
    SdrObjList* m_pObjList;
    sal_uInt32  m_nOrdNum;
    std::shared_ptr< SdrCaptionObj > m_pCaptionObj;

    void UnmarkObject();
    void BroadcastSwitchToPage();
    OUString GetDescriptionString( const char* pStrCacheID, bool bRepeat = false ) const;

public:
    ScUndoSdrCaptionObj(const std::shared_ptr< SdrCaptionObj >&);
    virtual ~ScUndoSdrCaptionObj() override;
};

class ScUndoDelSdrCaptionObj: public ScUndoSdrCaptionObj
{
public:
    ScUndoDelSdrCaptionObj(const std::shared_ptr< SdrCaptionObj >& pCaptionObj);
    virtual ~ScUndoDelSdrCaptionObj() override;

    virtual void    Undo() override;
    virtual void    Redo() override;

    virtual OUString GetComment() const override;
    virtual OUString GetSdrRepeatComment(SdrView& rView) const override;

    virtual void SdrRepeat(SdrView& rView) override;
    virtual bool CanSdrRepeat(SdrView& rView) const override;
};


class ScUndoNewSdrCaptionObj: public ScUndoSdrCaptionObj
{
public:
    ScUndoNewSdrCaptionObj(const std::shared_ptr< SdrCaptionObj >& pCaptionObj);
    virtual ~ScUndoNewSdrCaptionObj() override;

    virtual void    Undo() override;
    virtual void    Redo() override;

    virtual OUString GetComment() const override;
};

class ScUndoCursorAttr: public ScSimpleUndo
{
public:
diff --git a/sc/source/ui/undo/undocell.cxx b/sc/source/ui/undo/undocell.cxx
index fc9015d..04048d8 100644
--- a/sc/source/ui/undo/undocell.cxx
+++ b/sc/source/ui/undo/undocell.cxx
@@ -25,6 +25,12 @@
#include <editeng/justifyitem.hxx>
#include <svl/zforlist.hxx>
#include <svl/sharedstringpool.hxx>
#include <svx/dialmgr.hxx>
#include <svx/e3dsceneupdater.hxx>
#include <svx/svdocapt.hxx>
#include <svx/svdogrp.hxx>
#include <svx/svdviter.hxx>
#include <svx/strings.hrc>
#include <sfx2/app.hxx>

#include <attrib.hxx>
@@ -715,22 +721,183 @@ bool ScUndoThesaurus::CanRepeat(SfxRepeatTarget& rTarget) const
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
}


ScUndoSdrCaptionObj::ScUndoSdrCaptionObj(const std::shared_ptr< SdrCaptionObj >& pCaptionObj)
    : SdrUndoAction(pCaptionObj->getSdrModelFromSdrObject())
    , m_pObjList(pCaptionObj->getParentSdrObjListFromSdrObject())
    , m_nOrdNum(pCaptionObj->GetOrdNum())
    , m_pCaptionObj(pCaptionObj)
{
}

ScUndoSdrCaptionObj::~ScUndoSdrCaptionObj()
{
}

void ScUndoSdrCaptionObj::BroadcastSwitchToPage()
{
    if (m_pCaptionObj && m_pCaptionObj->IsInserted() && m_pCaptionObj->getSdrPageFromSdrObject())
    {
        SdrHint aHint(SdrHintKind::SwitchToPage, *m_pCaptionObj, m_pCaptionObj->getSdrPageFromSdrObject());
        rMod.Broadcast(aHint);
    }
}

void ScUndoSdrCaptionObj::UnmarkObject()
{
    SdrViewIter aIter( m_pCaptionObj.get() );
    for ( SdrView* pView = aIter.FirstView(); pView; pView = aIter.NextView() )
    {
        pView->MarkObj( m_pCaptionObj.get(), pView->GetSdrPageView(), true );
    }
}

OUString ScUndoSdrCaptionObj::GetDescriptionString(const char* pStrCacheID, bool bRepeat ) const
{
    const OUString rStr {SvxResId(pStrCacheID)};

    const sal_Int32 nPos = rStr.indexOf("%1");
    if (nPos < 0)
        return rStr;

    if (bRepeat)
        return rStr.replaceAt(nPos, 2, SvxResId(STR_ObjNameSingulPlural));

    return rStr.replaceAt(nPos, 2, m_pCaptionObj->TakeObjNameSingul());
}

ScUndoDelSdrCaptionObj::ScUndoDelSdrCaptionObj(const std::shared_ptr< SdrCaptionObj >& pCaptionObj)
    : ScUndoSdrCaptionObj(pCaptionObj)
{
}

ScUndoDelSdrCaptionObj::~ScUndoDelSdrCaptionObj()
{

}

void ScUndoDelSdrCaptionObj::Undo()
{
    // Trigger PageChangeCall
    BroadcastSwitchToPage();

    if (!m_pCaptionObj->IsInserted())
    {
        Point aOwnerAnchorPos(0, 0);

        if (dynamic_cast< const SdrObjGroup* >(m_pObjList->getSdrObjectFromSdrObjList()) != nullptr)
        {
            aOwnerAnchorPos = m_pObjList->getSdrObjectFromSdrObjList()->GetAnchorPos();
        }

        E3DModifySceneSnapRectUpdater aUpdater(m_pObjList->getSdrObjectFromSdrObjList());
        m_pObjList->InsertObject(m_pCaptionObj.get(), m_nOrdNum);

        if(aOwnerAnchorPos.X() || aOwnerAnchorPos.Y())
        {
            m_pCaptionObj->NbcSetAnchorPos(aOwnerAnchorPos);
        }
    }

}

void ScUndoDelSdrCaptionObj::Redo()
{
    if (m_pCaptionObj->IsInserted())
    {
        UnmarkObject();
        E3DModifySceneSnapRectUpdater aUpdater(m_pCaptionObj.get());
        m_pObjList->RemoveObject(m_nOrdNum);
    }

    // Trigger PageChangeCall
    BroadcastSwitchToPage();
}

OUString ScUndoDelSdrCaptionObj::GetComment() const
{
    return GetDescriptionString(STR_EditDelete);
}

void ScUndoDelSdrCaptionObj::SdrRepeat(SdrView& rView)
{
    rView.DeleteMarked();
}

bool ScUndoDelSdrCaptionObj::CanSdrRepeat(SdrView& rView) const
{
    return rView.AreObjectsMarked();
}

OUString ScUndoDelSdrCaptionObj::GetSdrRepeatComment(SdrView& /*rView*/) const
{
    return GetDescriptionString(STR_EditDelete, true);
}

ScUndoNewSdrCaptionObj::ScUndoNewSdrCaptionObj(const std::shared_ptr< SdrCaptionObj >& pCaptionObj)
    : ScUndoSdrCaptionObj(pCaptionObj)
{
}

ScUndoNewSdrCaptionObj::~ScUndoNewSdrCaptionObj()
{
}

void ScUndoNewSdrCaptionObj::Undo()
{
    // Trigger PageChangeCall
    BroadcastSwitchToPage();

    if (m_pCaptionObj->IsInserted())
    {
        UnmarkObject();
        m_pObjList->RemoveObject(m_nOrdNum);
    }
}

void ScUndoNewSdrCaptionObj::Redo()
{
    if (!m_pCaptionObj->IsInserted())
    {
        Point aAnchorPos( 0, 0 );

        if (dynamic_cast<const SdrObjGroup*>(m_pObjList->getSdrObjectFromSdrObjList()) != nullptr)
        {
            aAnchorPos = m_pCaptionObj->GetAnchorPos();
        }

        m_pObjList->InsertObject(m_pCaptionObj.get(), m_nOrdNum);

        // Arcs lose position when grouped (#i45952#)
        if ( aAnchorPos.X() || aAnchorPos.Y() )
        {
            m_pCaptionObj->NbcSetAnchorPos( aAnchorPos );
        }
    }

    // Trigger PageChangeCall
    BroadcastSwitchToPage();
}

OUString ScUndoNewSdrCaptionObj::GetComment() const
{
    return GetDescriptionString(STR_UndoInsertObj);
}

ScUndoReplaceNote::ScUndoReplaceNote( ScDocShell& rDocShell, const ScAddress& rPos,
        const ScNoteData& rNoteData, bool bInsert, SdrUndoAction* pDrawUndo ) :
    ScSimpleUndo( &rDocShell ),
    maPos( rPos ),
    mpDrawUndo( pDrawUndo )
{
    OSL_ENSURE( rNoteData.mxCaption, "ScUndoReplaceNote::ScUndoReplaceNote - missing note caption" );
    OSL_ENSURE( rNoteData.m_pCaption, "ScUndoReplaceNote::ScUndoReplaceNote - missing note caption" );
    if (bInsert)
    {
        maNewData = rNoteData;
        maNewData.mxCaption.setNotOwner();
    }
    else
    {
        maOldData = rNoteData;
        maOldData.mxCaption.setNotOwner();
    }
}

@@ -742,10 +909,8 @@ ScUndoReplaceNote::ScUndoReplaceNote( ScDocShell& rDocShell, const ScAddress& rP
    maNewData( rNewData ),
    mpDrawUndo( pDrawUndo )
{
    OSL_ENSURE( maOldData.mxCaption || maNewData.mxCaption, "ScUndoReplaceNote::ScUndoReplaceNote - missing note captions" );
    OSL_ENSURE( maOldData.m_pCaption || maNewData.m_pCaption, "ScUndoReplaceNote::ScUndoReplaceNote - missing note captions" );
    OSL_ENSURE( !maOldData.mxInitData.get() && !maNewData.mxInitData.get(), "ScUndoReplaceNote::ScUndoReplaceNote - unexpected uninitialized note" );
    maOldData.mxCaption.setNotOwner();
    maNewData.mxCaption.setNotOwner();
}

ScUndoReplaceNote::~ScUndoReplaceNote()
@@ -790,13 +955,13 @@ bool ScUndoReplaceNote::CanRepeat( SfxRepeatTarget& /*rTarget*/ ) const

OUString ScUndoReplaceNote::GetComment() const
{
    return ScResId( maNewData.mxCaption ?
        (maOldData.mxCaption ? STR_UNDO_EDITNOTE : STR_UNDO_INSERTNOTE) : STR_UNDO_DELETENOTE );
    return ScResId( maNewData.m_pCaption ?
        (maOldData.m_pCaption ? STR_UNDO_EDITNOTE : STR_UNDO_INSERTNOTE) : STR_UNDO_DELETENOTE );
}

void ScUndoReplaceNote::DoInsertNote( const ScNoteData& rNoteData )
{
    if( rNoteData.mxCaption )
    if( rNoteData.m_pCaption )
    {
        ScDocument& rDoc = pDocShell->GetDocument();
        OSL_ENSURE( !rDoc.GetNote(maPos), "ScUndoReplaceNote::DoInsertNote - unexpected cell note" );
@@ -808,7 +973,7 @@ void ScUndoReplaceNote::DoInsertNote( const ScNoteData& rNoteData )

void ScUndoReplaceNote::DoRemoveNote( const ScNoteData& rNoteData )
{
    if( rNoteData.mxCaption )
    if( rNoteData.m_pCaption )
    {
        ScDocument& rDoc = pDocShell->GetDocument();
        OSL_ENSURE( rDoc.GetNote(maPos), "ScUndoReplaceNote::DoRemoveNote - missing cell note" );
diff --git a/sc/source/ui/unoobj/editsrc.cxx b/sc/source/ui/unoobj/editsrc.cxx
index fb59b24..2989c6a 100644
--- a/sc/source/ui/unoobj/editsrc.cxx
+++ b/sc/source/ui/unoobj/editsrc.cxx
@@ -137,7 +137,7 @@ std::unique_ptr<SvxEditSource> ScAnnotationEditSource::Clone() const
SdrObject* ScAnnotationEditSource::GetCaptionObj()
{
    ScPostIt* pNote = pDocShell->GetDocument().GetNote(aCellPos);
    return pNote ? pNote->GetOrCreateCaption( aCellPos ) : nullptr;
    return pNote ? pNote->GetOrCreateCaption( aCellPos ).get() : nullptr;
}

SvxTextForwarder* ScAnnotationEditSource::GetTextForwarder()
diff --git a/sc/source/ui/unoobj/notesuno.cxx b/sc/source/ui/unoobj/notesuno.cxx
index 12e44a0..796ed04 100644
--- a/sc/source/ui/unoobj/notesuno.cxx
+++ b/sc/source/ui/unoobj/notesuno.cxx
@@ -216,7 +216,7 @@ uno::Reference < drawing::XShape > SAL_CALL ScAnnotationObj::getAnnotationShape(
    SolarMutexGuard aGuard;
    uno::Reference < drawing::XShape > xShape;
    if( const ScPostIt* pNote = ImplGetNote() )
        if( SdrObject* pCaption = pNote->GetOrCreateCaption( aCellPos ) )
        if( SdrObject* pCaption = pNote->GetOrCreateCaption( aCellPos ).get() )
            xShape.set( pCaption->getUnoShape(), uno::UNO_QUERY );
    return xShape;
}
diff --git a/sc/source/ui/view/drawview.cxx b/sc/source/ui/view/drawview.cxx
index 9069aed..51b281c 100644
--- a/sc/source/ui/view/drawview.cxx
+++ b/sc/source/ui/view/drawview.cxx
@@ -867,7 +867,7 @@ void ScDrawView::DeleteMarked()
        {
            // rescue note data for undo (with pointer to caption object)
            ScNoteData aNoteData = pNote->GetNoteData();
            OSL_ENSURE( aNoteData.mxCaption.get() == pCaptObj, "ScDrawView::DeleteMarked - caption object does not match" );
            OSL_ENSURE( aNoteData.m_pCaption.get() == pCaptObj, "ScDrawView::DeleteMarked - caption object does not match" );
            // collect the drawing undo action created while deleting the note
            if( bUndo )
                pDrawLayer->BeginCalcUndo(false);
diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx
index a159d44..a1598a2 100644
--- a/sc/source/ui/view/gridwin.cxx
+++ b/sc/source/ui/view/gridwin.cxx
@@ -360,7 +360,7 @@ static void lcl_UnLockComment( ScDrawView* pView, const Point& rPos, const ScVie
    ScDocument& rDoc = *pViewData->GetDocument();
    ScAddress aCellPos( pViewData->GetCurX(), pViewData->GetCurY(), pViewData->GetTabNo() );
    ScPostIt* pNote = rDoc.GetNote( aCellPos );
    SdrObject* pObj = pNote ? pNote->GetCaption() : nullptr;
    SdrObject* pObj = pNote ? pNote->GetCaption().get() : nullptr;
    if( pObj && pObj->GetLogicRect().IsInside( rPos ) && ScDrawLayer::IsNoteCaption( pObj ) )
    {
        const ScProtectionAttr* pProtAttr = rDoc.GetAttr( aCellPos, ATTR_PROTECTION );
diff --git a/sc/source/ui/view/notemark.cxx b/sc/source/ui/view/notemark.cxx
index af3a404..3df9dc4 100644
--- a/sc/source/ui/view/notemark.cxx
+++ b/sc/source/ui/view/notemark.cxx
@@ -67,7 +67,7 @@ ScNoteMarker::ScNoteMarker( vcl::Window* pWin, vcl::Window* pRight, vcl::Window*
ScNoteMarker::~ScNoteMarker()
{
    if (m_pModel)
        m_xObject.release();     // deleting pModel also deletes the SdrCaptionObj
        m_xObject.reset();     // deleting pModel also deletes the SdrCaptionObj

    InvalidateWin();

diff --git a/sc/source/ui/view/tabview5.cxx b/sc/source/ui/view/tabview5.cxx
index 8f95f23..058bedd 100644
--- a/sc/source/ui/view/tabview5.cxx
+++ b/sc/source/ui/view/tabview5.cxx
@@ -653,7 +653,7 @@ void ScTabView::OnLOKNoteStateChanged(const ScPostIt* pNote)
    if (!comphelper::LibreOfficeKit::isActive())
        return;

    const SdrCaptionObj* pCaption = pNote->GetCaption();
    const SdrCaptionObj* pCaption = pNote->GetCaption().get();
    if (!pCaption) return;

    tools::Rectangle aRect = pCaption->GetLogicRect();
diff --git a/sc/source/ui/view/viewfun6.cxx b/sc/source/ui/view/viewfun6.cxx
index f37d0d1..28c0340 100644
--- a/sc/source/ui/view/viewfun6.cxx
+++ b/sc/source/ui/view/viewfun6.cxx
@@ -495,7 +495,7 @@ void ScViewFunc::EditNote()
        /*  Drawing object has been created in ScDocument::GetOrCreateNote() or
            in ScPostIt::ShowCaptionTemp(), so ScPostIt::GetCaption() should
            return a caption object. */
        if( SdrCaptionObj* pCaption = pNote->GetCaption() )
        if( SdrCaptionObj* pCaption = pNote->GetCaption().get() )
        {
            if ( ScDrawView* pScDrawView = GetScDrawView() )
               pScDrawView->SyncForGrid( pCaption );